#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include "types.h"
#include "defs.h"
#include "params.h"
#include "lexer.h"
#include "preproc.h"
#include "parser.h"

#define ASSERT(fmt,arg...) {printf ("Lexer:");printf(fmt,##arg);exit(EXIT_FAILURE);}

int
scan_rtc (struct token * tk, char ** cp) {
    char * tp;
    if (**cp != '.') return ERROR;
    (*cp)++;
    tp = *cp;
    while (*tp) {
        if (isdigit(*tp) || isalpha (*tp)) // rtc只允许数字或字母
            tp++;
        else
            return ERROR;
    }
    // 此时tp指向0
    tk->str = *cp;
    tk->type = TK_RTC;
    *cp = tp+1;
    return SUCCESS;
}

int
scan_func (struct token * tk, char ** cp) {
    char * tp;
    if (**cp != '@') return ERROR;
    (*cp)++;
    tp = *cp;
    if (!isalpha(*tp)) return ERROR; // 函数名开头必须是字母
    while (*tp) {
        if (isdigit(*tp) || isalpha (*tp)) // func只允许数字或字母
            tp++;
        else
            return ERROR;
    }
    tk->str = *cp;
    tk->type = TK_FUNC;
    *cp = tp+1;
    return SUCCESS;
}

int
scan_lbl (struct token * tk, char ** cp) {
    char * tp;
    if (**cp != '%') return ERROR;
    (*cp)++;
    tp = *cp;
    while (*tp) {
        if (isdigit(*tp) || isalpha (*tp)) // lbl只允许数字或字母
            tp++;
        else
            return ERROR;
    }
    tk->str = *cp;
    tk->type = TK_LBL;
    *cp = tp+1;
    return SUCCESS;
}

int
scan_reg (struct token * tk, char ** cp) {
    char * tp;
    if (**cp != '$') return ERROR;
    (*cp)++;
    tp = *cp;
    if (!isalpha(*tp)) return ERROR; // reg开头必须是字母
    while (*tp) {
        if (isdigit(*tp) || isalpha (*tp)) 
            tp++;
        else
            return ERROR;
    }
    tk->str = *cp;
    tk->type = TK_REG;
    *cp = tp+1;
    return SUCCESS;
}

int
scan_vartype (struct token * tk, char ** cp) {
    char * tp;
    if (**cp != ':') return ERROR;
    (*cp)++;
    tp = *cp;
    if (!isalpha(*tp)) return ERROR; // vartype开头必须是字母
    while (*tp) {
        if (isdigit(*tp) || isalpha (*tp)) 
            tp++;
        else
            return ERROR;
    }
    tk->str = *cp;
    tk->type = TK_TYPE; 
    *cp = tp+1;
    return SUCCESS;
}

int
scan_char (struct token * tk, char ** cp) {
    char * tp;
    if (**cp != '\'') return ERROR;
    (*cp)++;
    tp = *cp; // *cp指向字符
    tp++;
    if (*tp != '\'')
        return ERROR;
    *tp = 0; // 消除字符后缀
    tp++;
    if (*tp != 0) // 后缀后还有多于字符
        return ERROR;
    tk->str = *cp;
    tk->num = (int64)*cp;
    tk->type = TK_IMM;
    *cp = tp+1;
    return SUCCESS;
}

int
scan_string (struct token * tk, char ** cp) {
    char * tp;
    if (**cp != '\"') return ERROR;
    (*cp)++;
    tp = *cp; // *cp指向首字符
    while (*tp) {
        if (*tp == '\"')
            break;
        tp++;
    }
    if (*tp == 0) return ERROR;
    *tp = 0; // 消除字符串后缀
    tp++;
    if (*tp != 0) return ERROR; // 字符串后缀后有字符
    tk->str = *cp;
    tk->type = TK_STR;
    *cp = tp+1;
    return SUCCESS;
}

int
scan_octnum (struct token * tk, char ** cp) {
    char * tp;
    uint64 i;
    int scanret;
    if (**cp != '0') return ERROR;
    tp = *cp; // *cp指向首字符
    scanret = sscanf (*cp, "%llo", &i);
    if (scanret == 0 || scanret == -1)
        return ERROR;
    while (*tp) tp++;
    tk->str = *cp;
    tk->num = i;
    tk->type = TK_IMM;
    *cp = tp+1;
    return SUCCESS;
}

int
scan_hexnum (struct token * tk, char ** cp) {
    char * tp;
    uint64 i;
    int scanret;
    if (**cp != '0') return ERROR;
    tp = *cp; // *cp指向首字符
    scanret = sscanf (*cp, "%llx", &i);
    if (scanret == 0 || scanret == -1)
        return ERROR;
    while (*tp) tp++;
    tk->str = *cp;
    tk->num = i;
    tk->type = TK_IMM;
    *cp = tp+1;
    return SUCCESS;
}

int
scan_decnum (struct token * tk, char ** cp) {
    char * tp;
    uint64 i;
    int scanret;
    if (!isdigit(**cp)) return ERROR;
    tp = *cp; // *cp指向首字符
    scanret = sscanf (*cp, "%lld", &i);
    if (scanret == 0 || scanret == -1)
        return ERROR;
    while (*tp) tp++;
    tk->str = *cp;
    tk->num = i;
    tk->type = TK_IMM;
    *cp = tp+1;
    return SUCCESS;
}

int
scan_alpha (struct token * tk, char ** cp) {
    char * tp;
    tp = *cp;
    if (!isalpha(*tp)) return ERROR; // 开头必须是字母
    while (*tp) {
        if (isdigit(*tp) || isalpha (*tp)) // 只允许数字或字母
            tp++;
        else
            return ERROR;
    }
    tk->str = *cp;
    tk->type = TK_INSVAR; // 可能是指令,也可能是变量
    *cp = tp+1;
    return SUCCESS;
}

int
scan_comma (struct token * tk, char ** cp) {
    char * tp;
    tp = *cp;
    if (*tp != ',') return ERROR;
    tp++;
    if (*tp != 0) return ERROR;
    tk->str = *cp;
    tk->type = TK_COMMA; 
    *cp = tp+1;
    return SUCCESS;
}


struct token *
scan (struct codeline * cl) {
    struct codeline * clptr; // 当前cl
    struct token tkhead;
    char *cp;
    uint tkn; // 第n个token
    struct token *tk, *prevtk; // 当前token和上一个token
    tkhead.next = NULL;
    prevtk = &tkhead;
    for (clptr=cl;clptr!=NULL;clptr=clptr->next) {
        cp = clptr->lnstr;
        for (tkn = clptr->tknum; tkn>0; tkn--) {
            tk = malloc (sizeof (struct token));
            tk->ln = clptr->ln;
            if (tk == NULL) ASSERT ("内存不足");
            switch (*cp) { // 首字母
                case 0: {
                    ASSERT ("意外的终结符,行:%u\n",clptr->ln);
                    goto next;
                }
                case '.': { // rtc
                    if (scan_rtc (tk, &cp)!=SUCCESS)
                        ASSERT ("错误的运行时命令,行:%u\n",clptr->ln);
                    goto next;
                }
                case '@' : { // 函数标签
                    if (scan_func (tk, &cp)!=SUCCESS)
                        ASSERT ("错误的函数名称,行:%u\n",clptr->ln);
                    goto next;
                }
                case '%' : { // 局部标签
                    if (scan_lbl (tk, &cp) != SUCCESS)
                        ASSERT ("错误的局部标签名称,行:%u\n",clptr->ln);
                    goto next;
                }
                case '$' : { // 寄存器
                    if (scan_reg (tk, &cp) != SUCCESS)
                        ASSERT ("错误的寄存器名称,行:%u\n",clptr->ln);
                    goto next;
                }
                case ':' : { // 类型
                    if (scan_vartype (tk, &cp) != SUCCESS)
                        ASSERT ("错误的类型名称,行:%u\n",clptr->ln);
                    goto next;
                }
                case '\'' : { // 字符 'c'
                    if (scan_char (tk, &cp) != SUCCESS)
                        ASSERT ("错误的字符定义,行:%u\n",clptr->ln);
                    goto next;
                }
                case '\"' : { // 字符串 "hello"
                    if (scan_string (tk, &cp) != SUCCESS)
                        ASSERT ("错误的字符串定义,行:%u\n",clptr->ln);
                    goto next;
                }
                case '0' : { // 8进制/16进制
                    if (*(cp+1) == 'x') { // 16进制
                        if (scan_hexnum (tk, &cp) != SUCCESS)
                            ASSERT ("错误的十六进制数字定义,行:%u\n",clptr->ln);
                    } else if (isdigit (*(cp+1))) { //8进制
                        if (scan_octnum (tk, &cp) != SUCCESS)
                            ASSERT ("错误的八进制数字定义,行:%u\n",clptr->ln);
                    } else {
                        ASSERT ("意外的数字,行:%u",clptr->ln);
                    }
                    goto next;
                }
            }
            if (isdigit (*cp)) { //数字
                if (scan_decnum (tk, &cp) != SUCCESS)
                    ASSERT ("错误的十进制数字定义,行:%u\n",clptr->ln);
                goto next;
            }
            if (isalpha (*cp)) { // 标识符或指令
                if (scan_alpha (tk, &cp) != SUCCESS)
                    ASSERT ("错误的标识符(指令或变量)定义,行:%u\n",clptr->ln);
                goto next;
            }
            if (*cp == ',') {
                if (scan_comma (tk, &cp) != SUCCESS)
                    ASSERT ("错误的标识符,行:%u\n",clptr->ln);
                goto next;
            }
            ASSERT ("意外的标识符,行:%u\n",clptr->ln);
            next:
            tk->next = NULL;
            prevtk->next = tk;
            prevtk = tk;
        }
        tk = malloc (sizeof (struct token));
        if (tk == NULL) ASSERT ("内存不足");
        tk->next = NULL;
        tk->type = TK_NEXT; // 下一行
        tk->ln = clptr->ln;
        prevtk->next = tk;
        prevtk = tk;
    }
    prevtk->type = TK_END;
    prevtk->next = NULL;
    tk->ln = -1;
    return tkhead.next;
}

struct token *
checktoken (struct token * tk) {
    struct token * tkp;
    tkp = tk;
    uint lineinitial;
    lineinitial = 1;
    while (tkp && tkp->type != TK_END) {
        if (tkp->type == TK_INSVAR) {
            if (lineinitial)
                tkp->type = TK_INS;
            else
                tkp->type = TK_VAR;
        }
        if (!(tkp->type==TK_FUNC || tkp->type==TK_RTC
           || tkp->type==TK_LBL))
            lineinitial = 0; // 非标签/运行时控制
        if (tkp->type == TK_NEXT)
            lineinitial = 1;
        tkp = tkp->next;
    }
    return tk;
}